package com.kanesoft.android.gdx.actors;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.kanesoft.android.gdx.control.WorldControl;
import com.kanesoft.android.gdx.widgets.GdxWidgets;
import com.kanesoft.android.gdx.widgets.WidgetEvents;

public abstract class ActorObject implements WidgetEvents {

    /* Attributes for to Box2D usage */
    protected Body actorBody;
    protected Fixture actorSensorFixture;
    protected WorldControl worldControl;
    protected float actionsStillTime;

    protected ActorPhysicsParameters objectPhysicsParams;

    protected boolean actorOrientatioFlipped;

    protected float actorScale;

    protected boolean isPhysicalObject;

    public ActorObject(float scale, WorldControl worldCtrl) {
        worldControl = worldCtrl;
        actorScale = scale;
        isPhysicalObject = false;
        worldCtrl.getEventsBroadcast().addActorObject(this);
    }

    public ActorObject(float scale, ActorPhysicsParameters physicsParams, WorldControl worldCtrl) {
        this(scale, worldCtrl);
        isPhysicalObject = true;
        objectPhysicsParams = physicsParams;
        initializActorSkeleton();
    }

    
    public WorldControl getWorldControl() {
        return worldControl;
    }
    
    public ActorPhysicsParameters getPhysicsParameters() {
        return objectPhysicsParams;
    }
    
    private void initializActorSkeleton() {
        if (worldControl == null) return;
        if (isPhysicalObject == false) return;

        float width = objectPhysicsParams.bodyWidth *actorScale;
        float height = objectPhysicsParams.bodyHeight *actorScale;
        float objectMass = 4/(actorScale*actorScale);
        
        World gameWorld = worldControl.getWorld();

        BodyDef def = new BodyDef();
        def.type = BodyType.DynamicBody;

        actorBody = gameWorld.createBody(def);

        PolygonShape poly = new PolygonShape();
        poly.setAsBox(width, height);
        Fixture bodyPhysics = actorBody.createFixture(poly, objectMass);
        poly.dispose();

        CircleShape circle = new CircleShape();
        circle.setRadius(width);
        circle.setPosition(new Vector2(0, -height));
        actorSensorFixture = actorBody.createFixture(circle, 0);
        circle.dispose();
        
        Vector2[] vertices = {new Vector2(-width,height+(height/2)), new Vector2(-width,height), new Vector2(width,height)};
        PolygonShape head = new PolygonShape();
        head.set(vertices);
        Fixture headPhysics = actorBody.createFixture(head, 0);
        head.dispose();

        bodyPhysics.setFriction(0f);
        headPhysics.setFriction(0f);

        actorBody.setBullet(true);
        actorBody.setFixedRotation(true);

        actorSensorFixture.setUserData(this);
        bodyPhysics.setUserData(this);
        headPhysics.setUserData(this);
    }

    public Fixture getSensorFixture() {
        return actorSensorFixture;
    }

    public Body getActorBody() {
        return actorBody;
    }

    public void updateActorPositions() {
        Vector2 pos = getActorBody().getPosition();
        
        getSensorFixture().setFriction(0.2f);


        setPosition(worldControl.convertGLPosXToPixel(pos.x - objectPhysicsParams.bodyWidth),
                worldControl.convertGLPosYToPixel(pos.y - (objectPhysicsParams.bodyHeight * 1.5f)));

    }

    public void setHorizontalFlip(boolean flip) {
        actorOrientatioFlipped = flip;
    }

    public boolean getHorizontalFlip() {
        return actorOrientatioFlipped;
    }

    public abstract void setPosition(int x, int y);

    public abstract Vector2 getPosition();

    public abstract GdxWidgets getActorWidget();

    public abstract void handleActorsCollision(ActorObject collidingActor);

    public abstract boolean isAttacking(ActorObject attacked);

    public abstract float getHitAceleration();


    public void destroyActor() {
        getActorWidget().enabled = false;
        if (getActorBody() != null) {
            getActorBody().destroyFixture(getSensorFixture());
            worldControl.getWorld().destroyBody(getActorBody());
        }
        worldControl.getEventsBroadcast().removeActorObject(this);
        getActorWidget().destroyWidget();
    }

}
